#ifndef B792C096_B35B_4292_9917_10B86CA7FFE2
#define B792C096_B35B_4292_9917_10B86CA7FFE2

#endif /* B792C096_B35B_4292_9917_10B86CA7FFE2 */

#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include "Log.hpp"

Log lg;

const int defaultfd = -1;
const string defaultip = "0.0.0.0";
const int backlog = 10;

enum
{
    UsageErr = 1,
    SocketErr,
    BindErr,
    ListenErr
};

class TcpServer;
class ThreadData
{
public:
    ThreadData(int fd, const string& ip, const uint16_t& port, TcpServer* t)
        :sockfd(fd),clientip(ip),clientport(port),tsvr(t)
    {}
public:
    int sockfd;
    string clientip;
    uint16_t clientport;
    TcpServer* tsvr;
};

class TcpServer
{
public:
    TcpServer(const uint16_t &port, const string &ip = defaultip)
        : listensock_(defaultfd), port_(port), ip_(ip)
    {
    }

    void Init()
    {
        // 创建套接字
        listensock_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listensock_ < 0)
        {
            lg(Fatal, "create socket, errno: %d, errstring: %s", errno, strerror(errno));
            exit(SocketErr);
        }
        lg(Info, "create socket success, listensock_: %d", listensock_);

        // 绑定套接字
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        inet_aton(ip_.c_str(), &(local.sin_addr));
        local.sin_addr.s_addr = 0;

        if (bind(listensock_, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            lg(Fatal, "bind err, errno: %d, errstring: %s", errno, strerror(errno));
            exit(BindErr);
        }
        lg(Info, "bind socket success, listensock_: %d", listensock_);

        // Tcp 面向连接的，处于监听状态 Listen
        if (listen(listensock_, backlog) < 0)
        {
            lg(Fatal, "listen err, errno: %d, errstring: %s", errno, strerror(errno));
            exit(ListenErr);
        }
        lg(Info, "listen socket success, listensock_: %d", listensock_);
    }

    static void* Routine(void* args)
    {
        pthread_detach(pthread_self());
        ThreadData* td = static_cast<ThreadData*>(args);
        td->tsvr->Service(td->sockfd, td->clientip, td->clientport);
        delete td;
        return nullptr;
    }

    void Start()
    {
        // while(true)
        // {
        //     lg(Info, "tcpServer is running...");
        //     sleep(1);
        // }

        lg(Info, "tcpServer is running...");
        for (;;)
        {
            // 1. 获取新连接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(listensock_, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                lg(Warning, "accept error, errno:%d, erstring: %s", errno, strerror(errno));
                continue; // 连接失败继续获取下一个
            }
            // 看看谁连接的我？
            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));

            // 2.根据新连接来进行通信
            lg(Info, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, clientip, clientport); // telnet 127.0.0.1 8888    测试

            // 开始服务version1——单进程版
            // Service(sockfd, clientip, clientport);
            // close(sockfd);

            // version2——多进程版
            // pid_t id = fork();
            // if (id == 0)
            // {
            //     // child
            //     close(listensock_);
            //     if (fork() > 0)
            //         exit(0);                           // 再创建子进程， 当前进程退出，留下孙子进程
            //     Service(sockfd, clientip, clientport); // 孙子进程执行任务，system领养
            //     close(sockfd);                         // 任务做完，关闭文件
            //     exit(0);
            // }
            // // father
            // pid_t rid = waitpid(id, nullptr, 0);
            // (void)rid;

            // version3——多线程版
            // ThreadData* td = new ThreadData(sockfd, clientip, clientport, this);
            // pthread_t tid;
            // pthread_create(&tid, nullptr, Routine, td);

            // version4——线程池版
            
        }
    }

    void Service(int sockfd, const string &clientip, const uint16_t &clientport)
    {
        // cs
        char buffer[1024];
        while (true)
        {
            ssize_t n = read(sockfd, buffer, sizeof(buffer));
            if (n > 0)
            {
                // 读取成功
                buffer[n] = 0;
                cout << "client say# " << buffer << endl;
                string echo_string = "tcpserver echo# ";
                echo_string += buffer;

                // 给客户端相应回来
                write(sockfd, echo_string.c_str(), echo_string.size());
            }
            else if (n == 0)
            {
                lg(Info, "%s:%d quit..., server close sockfd: %d", clientip.c_str(), clientport, sockfd);
                break;
            }
            else
            {
                lg(Warning, "read error, sockfd: %d, client ip: %s, client port: %d", sockfd, clientip.c_str(), clientport);
                break;
            }
        }
    }

    ~TcpServer()
    {
    }

private:
    // int sockfd_;
    int listensock_; // 监听套接字
    uint16_t port_;
    string ip_;
};